#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <event.h>
//#include <bufferevent.h>
//#include <buffer.h>
//#include <listener.h>

#define PORT        25341
#define BACKLOG     5
#define MEM_SIZE    1024

struct event_base* base;
struct sock_ev {
    struct event* read_ev;
    struct event* write_ev;
    char* buffer;
};

void release_sock_event(struct sock_ev* ev)
{
    event_del(ev->read_ev);
    event_free(ev->read_ev);
    event_free(ev->write_ev);
    free(ev->buffer);
    free(ev);
}

void on_write(int sock, short event, void* arg)
{
    char* buffer = (char*)arg;
    send(sock, buffer, strlen(buffer), 0);

    free(buffer);
}

void on_read(int sock, short event, void* arg)
{
    int size;
    struct sock_ev* ev = (struct sock_ev*)arg;
    ev->buffer = (char*)malloc(MEM_SIZE);
    bzero(ev->buffer, MEM_SIZE);
    size = recv(sock, ev->buffer, MEM_SIZE, 0);
    if (size == 0) {
        release_sock_event(ev);
        close(sock);
        return;
    }
    printf("receive data:%s, size:%d\n", ev->buffer, size);
    event_assign(ev->write_ev,base,sock, EV_WRITE, on_write, ev->buffer);
    event_add(ev->write_ev, NULL);
}

void on_accept(int sock, short event, void* arg)
{
    struct sockaddr_in cli_addr;
    int newfd, sin_size;
    sin_size = sizeof(struct sockaddr_in);
    newfd = accept(sock, (struct sockaddr*)&cli_addr, &sin_size);

    struct sock_ev* ev = (struct sock_ev*)malloc(sizeof(struct sock_ev));
    ev->write_ev = (struct event*)malloc(sizeof(struct event));
    ev->read_ev = event_new(base,newfd, EV_READ|EV_PERSIST, on_read, ev);
    event_add(ev->read_ev, NULL);
}

#if 0
const char *message = "hello,world!";
void listener_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sa, int socklen, void *user_data)
{
  struct event_base *base = (struct event_base*)user_data;
  struct bufferevent *bev;

  // 得到一个新的连接，通过连接 fd 构建一个 bufferevent
  bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
  if (!bev) 
  {
    fprintf(stderr, "Error constructing bufferevent!");
    event_base_loopbreak(base);
    return;
  }
  bufferevent_setwatermark(bev,EV_READ|EV_WRITE,20,0);
  //bufferevent_setwatermark(bev,EV_WRITE,20,1024);
  bufferevent_setcb(bev,on_read_bev, NULL, on_error_bev, NULL);
  bufferevent_enable(bev, EV_WRITE|EV_READ);
}
#endif

void on_read_bev(struct bufferevent *bev,void *ctx)
{
    int size;
    char buffer[MEM_SIZE]={0};

    size = bufferevent_read(bev, buffer, sizeof(buffer));
    printf("receive data:%s, size:%d\n", buffer, size);
    bufferevent_write(bev, buffer, size);
}

void on_error_bev(struct bufferevent *bev, short events, void *user_data)
{
    //if (events & BEV_EVENT_EOF) 
    if (events & EVBUFFER_EOF) 
    {
	printf("Connection closed.\n");
    } 
    //else if (events & BEV_EVENT_ERROR) 
    else if (events & EVBUFFER_ERROR) 
    {
	printf("Got an error on the connection: %s\n", strerror(errno));
    }
    else if (events & EVBUFFER_TIMEOUT)
    {
	printf("Read/Write data timeout!\n");
    }
    else
    {
	printf("on error,events = %x\n",events);
    }
    /* None of the other events can happen here, since we haven't enabled timeouts */
    bufferevent_free(bev);
}

void on_accept_bev(int sock, short event, void* arg)
{
    struct sockaddr_in cli_addr;
    int newfd, sin_size;
    sin_size = sizeof(struct sockaddr_in);
    newfd = accept(sock, (struct sockaddr*)&cli_addr, &sin_size);

    struct timeval tout;
    tout.tv_sec = 5;
    tout.tv_usec = 0;
    struct bufferevent *bev = bufferevent_socket_new(base, newfd, BEV_OPT_CLOSE_ON_FREE);
    //printf("%s:%d---bev = %p,base = %p,newfd = %d\n",__func__,__LINE__,bev,base,newfd);
    bufferevent_setwatermark(bev,EV_READ|EV_WRITE,20,0);
    bufferevent_set_timeouts(bev,&tout,&tout);
    //bufferevent_setwatermark(bev,EV_WRITE,20,1024);
    bufferevent_setcb(bev,on_read_bev, NULL, on_error_bev, NULL);
    bufferevent_enable(bev, EV_WRITE|EV_READ);
}

int main(int argc, char* argv[])
{
    struct sockaddr_in my_addr;
    int sock;

    memset(&my_addr, 0, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(PORT);
    my_addr.sin_addr.s_addr = INADDR_ANY;

    base = event_base_new();
#if 1
    sock = socket(AF_INET, SOCK_STREAM, 0);
    int yes = 1;
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
    bind(sock, (struct sockaddr*)&my_addr, sizeof(struct sockaddr));
    listen(sock, BACKLOG);

    struct event listen_ev;
    //event_assign(&listen_ev,base,sock, EV_READ|EV_PERSIST, on_accept, NULL);
    event_assign(&listen_ev,base,sock, EV_READ|EV_PERSIST, on_accept_bev, NULL);
    event_add(&listen_ev, NULL);
    event_base_dispatch(base);
#else
    struct evconnlistener *listener;
    listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
	    LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr*)&my_addr, sizeof(my_addr));
#endif
    event_base_free(base);

    return 0;
}

